#!/usr/bin
# -*- coding: utf-8 -*-

import mod_parameters as params
import mod_problem as pr
import mod_node as nd
import mod_element as el
import mod_section as sec
import mod_material as mat
import mod_domain as dom
import mod_mesh as msh

TCI = params.PARAMS["testConstructorsInputs"]

# ==============================================================================
class ParserDat():
    """ This generic class describes the data structure a parser must create
    in order to match the finite element requirements
    """
    NAME = "Parser for dat files"
    FILE_EXTENSION = ".dat"
    COMMENT_CHARACTER = "#"
    NAME_VALUE_SEPARATOR = "="

    # --------------------------------------------------------------------------
    def __init__(self):
        self.nds = []
        self.ndsSets = []
        self.els = []
        self.elsSets = []
        self.edgs = []
        self.mshs = []
        self.secs = []
        self.mats = []
        self.doms = []
        self.bnds = []
        self.bcs = []
        self.lcs = []

    # --------------------------------------------------------------------------
    def readFile(self, fileName):
        """ This function reads the input file data structure.
        The formating of this data structure to the one of iCafe
        is the role of the self.finilizeDataStructure() method.
        """
        try:
            file = open(fileName, "r")
        except:
            raise InputError, "Can not open " + fileName

        iLine = 0
        while True:
            line = file.readline()

            if not line:
                break
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            if len(line) > 0:
                # this is not a blank line
                if line[0] != ParserDat.COMMENT_CHARACTER:
                    # this is not a comment line
                    if not line[-1] == ":":
                        print "line:", line
                        raise ValueError, "Line " + str(iLine) + " must end with a :"
                    line = line[:-1]
                    line = line.split(",")
                    keyword = line[0]

                    if keyword == "nodes":
                        self.readNodes(file, line, iLine)
                        print "nds\n", self.nds, iLine

                    elif keyword == "nodesSet":
                        self.readNodesSet(file, line, iLine)
                        print "ndsSets\n", self.ndsSets, iLine

                    elif keyword == "elements":
                        self.readElements(file, line, iLine)
                        print "els\n", self.els

                    elif keyword == "elementsSet":
                        self.readElementsSet(file, line, iLine)
                        print "elsSets\n", self.elsSets

                    elif keyword == "section" :
                        self.readSection(file, line, iLine)
                        print "secs\n", self.secs

                    elif keyword == "material":
                        self.readMaterial(file, line, iLine)
                        print "mats\n", self.mats

                    elif keyword == "edges":
                        self.readEdges(file, line, iLine)
                        print "edgs\n", self.edgs

                    elif keyword == "mesh":
                        self.readMesh(file, line, iLine)
                        print "mshs\n", self.mshs

                    elif keyword == "domain":
                        self.readDomain(file, line, iLine)
                        print "doms\n", self.doms

                    elif keyword == "boundaries":
                        self.readBoundaries(file, line, iLine)
                        print "bnds\n", self.bnds

                    elif keyword == "boundaryCondition":
                        self.readBoundaryCondition(file, line, iLine)
                        print "bcs\n", self.bcs

                    elif keyword == "loadCondition":
                        self.readLoadCondition(file, line, iLine)
                        print "lcs\n", self.lcs

                    else:
                        raise ValueError, "Line " + str(iLine) + \
                                          ": unknown keyword " + keyword

        file.close()

    # --------------------------------------------------------------------------
    def readNodes(self, file, line, iLine):
        # arguments lines
        line = file.readline()
        lLine = len(line)
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                uId = line[0]
                x, y, z = float(line[1]), float(line[2]), float(line[3])
                self.nds.append((uId, x, y, z))
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create node."
            line = file.readline()
        file.seek(lastPos)

    # --------------------------------------------------------------------------
    def readNodesSet(self, file, line, iLine):
        # keywordline
        line = line[1].split("=")
        if line[0] != "name":
            raise ValueError, "Line " + str(iLine) + \
                              ": nodesSet keyword needs 'name' argument."
        else:
            name = line[1]

        # arguments lines
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                ndsUIds = line
                self.ndsSets.append((name, ndsUIds))
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create nodesSet."
            line = file.readline()
        file.seek(lastPos)

    # --------------------------------------------------------------------------
    def readElements(self, file, line, iLine):
        line = line[1].split("=")
        if line[0] != "type":
            raise ValueError, "Line " + str(iLine) + \
                              ": element keyword needs 'type' argument."
        else:
            typ = line[1]

        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                uId = line[0]
                ndsUIds = line[1:]
                self.els.append((uId, typ, ndsUIds))
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create element."
            line = file.readline()
        file.seek(lastPos)

    # --------------------------------------------------------------------------
    def readElementsSet(self, file, line, iLine):
        line = line[1].split("=")
        if line[0] != "name":
            raise ValueError, "Line " + str(iLine) + \
                              ": elementsSet keyword needs 'name' argument."
        else:
            name = line[1]

        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                elsUIds = line
                self.elsSets.append((name, elsUIds))
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create elementsSet."
            line = file.readline()
        file.seek(lastPos)

    # --------------------------------------------------------------------------
    def readMaterial(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            arg = arg.split("=")
            argKey = arg[0]
            argVal = arg[1]
            args[argKey] = argVal

        try:
            uId = args["name"]
            typ = args["type"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": material keyword needs 'name'" + \
                              " and 'type' arguments"

        params = {}
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            for arg in line:
                argKey, argVal = arg.split("=")
                params[argKey] = argVal
            line = file.readline()

        self.mats.append((uId, params))
        file.seek(lastPos)

    # --------------------------------------------------------------------------
    def readSection(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            arg = arg.split("=")
            argKey = arg[0]
            argVal = arg[1]
            args[argKey] = argVal

        try:
            uId = args["name"]
            typ = args["type"]
            mat = args["material"]
            elsSet = args["elementsSet"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": section keyword needs 'name', 'type'" + \
                              ", 'material' and 'elementsSet' arguments"

        params = {}
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            for arg in line:
                argKey = arg[0]
                argVal = arg[1]
                params[argKey] = argVal
            line = file.readline()

        self.secs.append((uId, typ, mat, elsSet))
        file.seek(lastPos)


    def readEdges(self, file, line, iLine):
        line = line[1].split("=")
        if line[0] != "type":
            raise ValueError, "Line " + str(iLine) + \
                              ": edges keyword needs 'type' argument."
        else:
            typ = line[1]

        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                uId = line[0]
                ndsUIds = line[1:]
                self.edgs.append((uId, typ, ndsUIds))
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create edge."
            line = file.readline()
        file.seek(lastPos)

    def readMesh(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            arg = arg.split("=")
            argKey = arg[0]
            argVal = arg[1]
            args[argKey] = argVal

        try:
            uId = args["name"]
            typ = args["type"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": mesh keyword needs 'name'" + \
                              " and 'type' arguments"

        elsUIds = []
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")
            try:
                for elUId in line:
                    elsUIds.append(elUId)
            except:
                raise ValueError, "Line " + str(iLine) + \
                                  ": can not create mesh."
            line = file.readline()

        self.mshs.append((uId, typ, elsUIds))
        file.seek(lastPos)


    def readDomain(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            argKey, argVal = arg.split("=")
            args[argKey] = argVal

        try:
            uId = args["name"]
            typ = args["type"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": d keyword needs 'name'" + \
                              " and 'type' arguments"

        mshsUIds = []
        edgsUIds = []
        domsUIds = []
        bndsUIds = []
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            argKey, argVal = line.split("=")
            args[argKey] = argVal
            line = file.readline()

        try:
            if typ == "domain":
                edgsUIds.append(args["edges"])
                mshsUIds.append(args["meshes"])
                self.doms.append((uId, typ, mshsUIds, edgsUIds))
            elif typ == "globalDomain":
                domsUIds.append(args["domains"])
                bndsUIds.append(args["boundaries"])
                self.doms.append((uId, typ, domsUIds, bndsUIds))

        except:
            if typ == "domain":
                raise ValueError, "Line " + str(iLine) + \
                                  ": domain keyword argument needs 'edges'" + \
                                  " and 'meshes' arguments"
            elif typ == "globalDomain":
                raise ValueError, "Line " + str(iLine) + \
                                  ": globalDomain keyword argument needs 'domains'" + \
                                  " and 'boundaries' arguments"
        file.seek(lastPos)


    def readBoundaries(self, file, line, iLine):
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            line = line.split(",")

            uId = line[0]
            domain1 = line[1]
            edge1 = line[2]
            domain2 = line[3]
            edge2 = line[4]

            self.bnds.append((uId, domain1, edge1, domain2, edge2))
            line = file.readline()
        file.seek(lastPos)

    def readBoundaryCondition(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            arg = arg.split("=")
            argKey = arg[0]
            argVal = arg[1]
            args[argKey] = argVal

        try:
            uId = args["name"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": boundaryCondition keyword needs 'name'" + \
                              " arguments"

        args = {}
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            argKey, argVal = line.split("=")
            args[argKey] = argVal
            line = file.readline()

        print args
        try:
            edges = args["edges"]
            dofs = args["dofs"]
            vals = args["values"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": boundaryCondition keyword argument needs " + \
                              "'edges', 'dofs' and 'values'"

        self.bcs.append((uId, edges, dofs, vals))
        file.seek(lastPos)

    def readLoadCondition(self, file, line, iLine):
        args = {}
        for arg in line[1:]:
            argKey, argVal = arg.split("=")
            args[argKey] = argVal

        try:
            uId = args["name"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": boundaryCondition keyword needs 'name'" + \
                              " arguments"

        args = {}
        line = file.readline()
        while line[:4] == "    ":
            lastPos = file.tell()
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            argKey, argVal = line.split("=")
            args[argKey] = argVal
            line = file.readline()

        try:
            edges = args["edges"]
            duals = args["duals"]
            vals = args["values"]
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": boundaryCondition keyword argument needs " + \
                              "'edges', 'duals' and 'values'"

        self.lcs.append((uId, edges, duals, vals))
        file.seek(lastPos)

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def buildMesh(self, problem):
        for mshUId, mshTyp, mshEls in self.mshs:
            mesh = msh.Mesh()



    def buildCodeDataStructure(self, problem):
        """ This function makes the interface between the input file
        data structure and iCafe data structure."""
        if TCI:
            if not isinstance(problem, pr.Problem):
                raise ValueError, "A Problem object is need to build " + \
                                  "the code data structure."

        self.buildMesh(problem)
        print "titi et ro minet"

# ==============================================================================
def buildParser(fileExt):
    if fileExt == "dat":
        return ParserDat()
    else:
        raise NotImplementedError, "The parser for input file with " + \
                                   "extension" + fileExt + " is not available."


# ==============================================================================
if __name__ == "__main__":
    parser = ParserDat()
    parser.readFile("castest1.dat")
